﻿/* 
 *  Created By: Tom Shirley
 *  Project URL: http://www.codeplex.com/accesschecker
 *  License: GNU GPL v2
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Utilities;
using System.Globalization;

namespace TomShirley.WebParts.AccessChecker
{
    /// <summary>
    /// Display a tree heirarchy of nodes representing SPWeb and SPList objects, showing either 
    /// a) A specified user's access to the objects
    /// b) Whether each object inherits its permission settings from its parent or has unique permissions defined
    /// 
    /// To use this control:
    /// 1. Create a new instance, passing in the guid of the web which is to be the root node of the tree, and its site guid.
    /// 2. Populate the tree by calling either GenerateUserAccessTree() or GeneratePermissionInheritanceTree(), depending
    ///    on which mode you require. The function's parameters can be obtained from the user by using the AccessCheckerInputForm class.
    /// 3. Register the javascript returned from GetColourCodingScript(), which will colour code nodes in the tree.
    /// </summary>
    public class SPPermissionsTreeView : TreeView
    {
        #region Private Properties
        /// <summary>
        /// If true, any sub-webs of the root SPWeb object, whose guid is at the bottom of the _webGuid stack, are included when generating the permission tree.
        /// </summary>
        private bool _DisplaySubWebs;

        /// <summary>
        /// Determines which nodes in the tree should be filtered out.
        /// </summary>
        private TreeNodeFilterState _FilterState;

        /// <summary>
        /// Stores the mode of the Tree, i.e. 'User' Mode or 'Web' Mode.
        /// </summary>
        private AccessCheckerMode _Mode;

        private bool _IsRunningAsAdmin;
        /// <summary>
        /// UTC time that the tree view completed generating its tree node heirarchy.
        /// </summary>
        private DateTime _TimeGenerated;
        private const int MAX_NODE_DEPTH = 30;

        /// <summary>
        /// Specifies the User that the permission tree is generated for. This property is null if the _Mode is 'Web', i.e. Permission Inheritance mode.
        /// </summary>
        private SPPrincipalInfo _PrincipalInfo;
        /// <summary>
        /// Specifices the permission masks that the User needs to have on each SharePoint object that is checked for access. This property is null if the _Mode is 'Web', i.e. Permission Inheritance mode.
        /// </summary>
        private SPBasePermissions _BasePermissions;

        /// <summary>
        /// Stack maintaining list of web guid's. This property is used when expanding webs as the app pool.
        /// </summary>
        private Stack<Guid> _webGuid = new Stack<Guid>();
        /// <summary>
        /// If true, indicates that the sub-web, determined by the value of _subWebGuid, is to be expanded. This property is only used when
        /// expanding the tree as the App Pool account. See RunExpandWebAsAdmin().
        /// </summary>
        private bool _expandSubWebOnly;
        /// <summary>
        /// Current subweb ID, used to open a subweb as the app pool account.
        /// </summary>
        private Guid _subWebGuid = Guid.Empty;
        /// <summary>
        /// Stack maintaining the current sub web's Guid. This property is used when expanding webs as the app pool.
        /// </summary>
        private Stack<int> _subWebIndex = new Stack<int>();
        /// <summary>
        /// Index of a SPList in the current SPWeb's Lists collection, used to obtain a reference to
        /// a list as the app pool account.
        /// </summary>
        private Stack<int> _listIndex = new Stack<int>();
        /// <summary>
        /// Current SPSite's ID, used to obtain a reference to the site as the app pool account.
        /// </summary>
        private Guid _siteGuid = Guid.Empty;
        /// <summary>
        /// Stores a node that represents a list. This property used when the current user does not
        /// have permissions to the current list being processed. See RunWithElevatedPrivileges().
        /// </summary>
        private SPPermissionsTreeNode _listTreeNode = null;
        /// <summary>
        /// Stores a node that represents a web. This property used when the current user does not
        /// have permissions to the current web being processed. See RunWithElevatedPrivileges().
        /// </summary>
        private SPPermissionsTreeNode _webTreeNode = null;

        private const string valuePathDivTagStart = "<div class=\"ACWP-TreeNodeValuePath\" style=\"display:none\" >";
        private const string valuePathDivTagEnd = "</div>";

        #endregion

        #region Public Properties
        /// <summary>
        /// UTC time that the tree view completed generating its tree node heirarchy.
        /// </summary>
        /// <value>DateTime object (UTC)</value>
        public DateTime TimeGenerated
        {
            get { return _TimeGenerated; }
        }

        public AccessCheckerMode Mode
        {
            get { return _Mode; }
        }


        #endregion

        #region Private Methods
        /// <summary>
        /// Generate the SPPermissionsTreeView nodes. 
        /// </summary>
        /// <param name="displaySubWebs">if set to <c>true</c> [display sub webs].</param>
        /// <param name="filterState">State of the filter.</param>
        private void GenerateTree(bool displaySubWebs, TreeNodeFilterState filterState)
        {
            SPWeb web = null;
            SPSite site = null;

            this._DisplaySubWebs = displaySubWebs;
            this._FilterState = filterState;

            // The client side script to colour code nodes needs to know the mode of this control
            this.Attributes.Add("ShowUserOrWebPermissions", this._Mode.ToString());

            try
            {
                site = new SPSite(this._siteGuid);
                web = site.OpenWeb(this._webGuid.Pop());
                this.Nodes.Add(ExpandWeb(site, web, 0, MAX_NODE_DEPTH, true)); // Starts population of tree nodes
            }
            finally
            {
                if (web != null)
                    web.Dispose();

                if (site != null)
                    site.Dispose();
            }

            this._TimeGenerated = DateTime.UtcNow;

            foreach (SPPermissionsTreeNode node in this.Nodes)
            {
                AppendTreeNodeValuePathToText(node);
            }
        }

        /// <summary>
        /// Return a TreeNode containing all child SPWeb and SPList nodes, up to a maximum depth level, for a specified SPWeb.

        /// </summary>
        /// <param name="currentWeb">The current web.</param>
        /// <param name="currentDepth">The current depth.</param>
        /// <param name="maxDepth">The max depth.</param>
        /// <param name="isRootNode">Is the web the root web.</param>
        /// <returns>TreeNode containing the current Web's subwebs and lists down to a specified depth.</returns>
        private SPPermissionsTreeNode ExpandWeb(SPSite currentSite, SPWeb currentWeb, int currentDepth, int maxDepth, bool isRootWeb)
        {
            SPWeb currentSubWeb = null;
            SPPermissionsTreeNode currentNode = null, childNodes = null;
            SPWeb tempWeb = null;

            try
            {
                _webGuid.Push(currentWeb.ID);
                if (currentWeb != null)
                {
                    try
                    {
                        currentNode = CreateTreeNode(currentWeb.ServerRelativeUrl,
                                            "", "/_layouts/images/AccessChecker/LINK.GIF",
                                            GetEditPermissionsURL(currentWeb, currentWeb.Url), "_blank", currentWeb);

                        currentNode.Value = "SPWeb|" + currentWeb.ID.ToString() + "|" + currentNode.PermissionType.ToString();

                        ExpandLists(currentNode, currentWeb); // Add Lists to current web's treeNode
                        // Add the current web's subweb nodes if:
                        // 1. The user wants to display the Sub Webs, set in the WP property DisplaySubWebs
                        // 2. The current node depth is less than the max depth.
                        if (this._DisplaySubWebs && currentDepth < maxDepth)
                        {
                            // Add each subweb node to the current nodes children.  
                            for (int i = 0; i < currentWeb.Webs.Count; i++)
                            {
                                try
                                {
                                    _subWebIndex.Push(i);
                                    // NOTE: currentWeb.Webs[i] can succeed without throwing a security exception, whilst OpenWeb() will throw an exception. Therefore, to obtain the subweb object, use OpenWeb().
                                    try
                                    {
                                        tempWeb = currentWeb.Webs[i];
                                        currentSubWeb = currentSite.OpenWeb(tempWeb.ID);
                                    }
                                    finally
                                    {
                                        if (tempWeb != null)
                                            tempWeb.Dispose();
                                    }
                                    childNodes = ExpandWeb(currentSite, currentSubWeb, currentDepth + 1, maxDepth, false);

                                    if (childNodes != null)
                                        currentNode.ChildNodes.Add(childNodes);
                                }
                                catch (System.UnauthorizedAccessException e)
                                {
                                    SPPermissionsTreeNode tempTreeNode = RunExpandWebAsAdmin(true);
                                    if (tempTreeNode != null)
                                        currentNode.ChildNodes.Add(tempTreeNode);
                                }
                                finally
                                {
                                    if (currentSubWeb != null)
                                    {
                                        currentSubWeb.Dispose();
                                    }
                                    _subWebIndex.Pop();
                                }
                            }
                        }


                        if (isRootWeb) // Root Node should never be hidden
                            return currentNode;
                        else
                        {
                            if (currentNode.HideNode(currentWeb, this._FilterState))
                                return null;
                            else
                                return currentNode;
                        }
                    }
                    catch (System.UnauthorizedAccessException e)
                    {
                        return RunExpandWebAsAdmin(false); // currentWeb.Webs failed, so expand the web as admin
                    }
                }
                return null;
            }
            finally
            {
                if (currentWeb != null)
                    currentWeb.Dispose();

                if (currentSite != null)
                    currentSite.Dispose();

                _webGuid.Pop();
            }
        }

        /// <summary>
        /// Expands the lists of an SPWeb object.
        /// </summary>
        /// <param name="currentNode">The current node.</param>
        /// <param name="currentWeb">The current web.</param>
        private void ExpandLists(SPPermissionsTreeNode currentNode, SPWeb currentWeb)
        {
            if (_IsRunningAsAdmin)
                GetListTreeNodes(currentNode, currentWeb);
            else
            {
                try
                {
                    _listTreeNode = currentNode;
                    _webGuid.Push(currentWeb.ID);
                    _IsRunningAsAdmin = true;
                    SPSecurity.CodeToRunElevated elevatedGetListTreeNodesAsAdmin = new SPSecurity.CodeToRunElevated(GetListTreeNodesAsAdmin);
                    SPSecurity.RunWithElevatedPrivileges(elevatedGetListTreeNodesAsAdmin);
                }
                finally
                {
                    _IsRunningAsAdmin = false;
                    _webGuid.Pop();
                }
            }
        }

        /// <summary>
        /// Gets the list tree nodes of an SPWeb.
        /// </summary>
        /// <param name="currentNode">The current node that the new list nodes are to be added to.</param>
        /// <param name="currentWeb">The current web.</param>
        private void GetListTreeNodes(SPPermissionsTreeNode currentNode, SPWeb currentWeb)
        {
            int i;
            SPList currentList = null;

            if (currentNode != null && currentWeb != null)
            {
                SortedList<string, List<SPPermissionsTreeNode>> sl = new SortedList<string, List<SPPermissionsTreeNode>>();

                for (i = 0; i < currentWeb.Lists.Count; i++)
                {
                    try
                    {
                        _listIndex.Push(i);
                        currentList = currentWeb.Lists[i];

                        if (currentList.Hidden != true)
                        {
                            SPPermissionsTreeNode tnList = CreateTreeNode(
                                string.Format("{0} ({1})", currentList.Title,
                                currentList.ItemCount), "", currentList.ImageUrl, GetEditPermissionsURL(currentList, currentWeb.Url), "_blank",
                                currentList);

                            tnList.Value = "SPList|" + currentList.ID.ToString() + "|" + tnList.PermissionType.ToString();

                            if (!tnList.HideNode(currentList, this._FilterState))
                                AddTreeNodeToSortedList(tnList, sl, tnList.Text);
                        }
                    }
                    catch (System.UnauthorizedAccessException e)
                    {
                        SPSecurity.CodeToRunElevated elevatedGetListTreeNodeAsAdmin = new SPSecurity.CodeToRunElevated(GetListTreeNodeAsAdmin);
                        SPSecurity.RunWithElevatedPrivileges(elevatedGetListTreeNodeAsAdmin);
                        if (_listTreeNode != null)
                            AddTreeNodeToSortedList(_listTreeNode, sl, _listTreeNode.Text);
                    }
                    finally
                    {
                        _listIndex.Pop();
                    }
                }

                foreach (string key in sl.Keys)
                {
                    foreach (SPPermissionsTreeNode currentTreeNode in sl[key])
                    {
                        currentNode.ChildNodes.Add(currentTreeNode);
                    }
                }
            }
        }

        /// <summary>
        /// Create a child-class instance of SPPermissionsTreeNode, depending on the Mode of this Tree View, to be
        /// added to this TreeView's nodes collection.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="value"></param>
        /// <param name="imageUrl"></param>
        /// <param name="navigateUrl"></param>
        /// <param name="target"></param>
        /// <param name="securableObject"></param>
        /// <returns></returns>
        private SPPermissionsTreeNode CreateTreeNode(string text, string value, string imageUrl, string navigateUrl, string target, ISecurableObject securableObject)
        {
            if (this._Mode == AccessCheckerMode.User)
                return new SPUserAccessTreeNode(text,
                                value, imageUrl,
                                navigateUrl, target, securableObject,
                                _PrincipalInfo, _BasePermissions);
            else
                return new SPPermissionInheritanceTreeNode(text,
                                value, imageUrl,
                                navigateUrl, target, securableObject);
        }

        /// <summary>
        /// Add a SPPermissionsTreeNode object to a specified SortedList of type <string, List<SPPermissionsTreeNode>>
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="sortedList"></param>
        /// <param name="key"></param>
        private void AddTreeNodeToSortedList(SPPermissionsTreeNode treeNode, SortedList<string, List<SPPermissionsTreeNode>> sortedList, string key)
        {
            if (sortedList.ContainsKey(key) && sortedList[key] != null)
                sortedList[key].Add(treeNode);
            else
            {
                if (!key.Equals(""))
                {
                    List<SPPermissionsTreeNode> treeNodeList = new List<SPPermissionsTreeNode>();
                    treeNodeList.Add(treeNode);
                    sortedList.Add(key, treeNodeList);
                }
            }
        }

        #region Expand object as App Pool account functions

        /// <summary>
        /// Execute the ExpandWebAsAdmin() function as the app pool account.
        /// </summary>
        /// <param name="expandSubWebOnly">if set to <c>true</c> [expand sub web only].</param>
        /// <returns>TreeNode object containing the web and list nodes</returns>
        private SPPermissionsTreeNode RunExpandWebAsAdmin(bool expandSubWebOnly)
        {
            _expandSubWebOnly = expandSubWebOnly;
            SPSecurity.CodeToRunElevated elevatedExpandWebAsAdmin = new SPSecurity.CodeToRunElevated(ExpandWebAsAdmin);
            SPSecurity.RunWithElevatedPrivileges(elevatedExpandWebAsAdmin);

            return _webTreeNode;
        }

        /// <summary>
        /// Expands the current Web whilst running in the context of the app pool.
        /// </summary>
        private void ExpandWebAsAdmin()
        {
            SPSite site = null;
            SPWeb currentWeb = null;
            SPWeb tempWeb = null;

            if (_webGuid.Count == 0 || _siteGuid == Guid.Empty || _subWebIndex.Count == 0)
                throw new ApplicationException("Could not Expand Web as Admin. Empty web/site guid");

            try
            {
                site = new SPSite(_siteGuid);
                currentWeb = site.OpenWeb(_webGuid.Peek());

                if (_expandSubWebOnly == true)
                {
                    tempWeb = currentWeb.Webs[_subWebIndex.Peek()];

                    _webTreeNode = ExpandWeb(site, tempWeb, 0, MAX_NODE_DEPTH, false);
                }
                else
                    _webTreeNode = ExpandWeb(site, currentWeb, 0, MAX_NODE_DEPTH, false);
            }
            catch (Exception e)
            {
                _webTreeNode = null;
                throw;
            }
            finally
            {
                if (site != null)
                    site.Dispose();

                if (currentWeb != null)
                    currentWeb.Dispose();

                if (tempWeb != null)
                    tempWeb.Dispose();
            }
        }

        /// <summary>
        /// Gets the list tree nodes as admin.
        /// </summary>
        private void GetListTreeNodesAsAdmin()
        {
            SPSite site = null;
            SPWeb currentWeb = null;

            if (_webGuid.Count == 0 || _siteGuid == Guid.Empty)
                throw new ApplicationException("Could not obtain List TreeNode as Admin. Empty web/site guid");

            try
            {
                site = new SPSite(_siteGuid);
                currentWeb = site.OpenWeb(_webGuid.Peek());

                if (_listTreeNode != null)
                    GetListTreeNodes(_listTreeNode, currentWeb);
            }
            catch (Exception e)
            {
                _listTreeNode = null;
                throw;
            }
            finally
            {
                if (site != null)
                    site.Dispose();

                if (currentWeb != null)
                    currentWeb.Dispose();
            }
        }

        /// <summary>
        /// Gets a list tree node as admin.
        /// </summary>
        private void GetListTreeNodeAsAdmin()
        {
            SPSite site = null;
            SPWeb currentWeb = null;
            SPList currentList = null;

            if (_webGuid.Count == 0 || _siteGuid == Guid.Empty || _listIndex.Count == 0)
                throw new ApplicationException(Properties.Resources.Error_Obtaining_List_Tree_Node_As_Admin);

            try
            {
                site = new SPSite(_siteGuid);
                currentWeb = site.OpenWeb(_webGuid.Peek());
                currentList = currentWeb.Lists[_listIndex.Peek()];


                _listTreeNode = CreateTreeNode(string.Format("{0} ({1})", currentList.Title,
                                             currentList.ItemCount), "", currentList.ImageUrl,
                                             GetEditPermissionsURL(currentList, currentWeb.Url), "_blank", currentList);
                _listTreeNode.Value = "SPList|" + currentList.ID.ToString() + "|" + this._listTreeNode.PermissionType.ToString();
                _listTreeNode.PopulateOnDemand = false;

                if (_listTreeNode.HideNode(currentList, this._FilterState))
                    _listTreeNode = null;

            }
            catch (Exception e)
            {
                _listTreeNode = null;
                throw;
            }
            finally
            {

                if (site != null)
                    site.Dispose();

                if (currentWeb != null)
                    currentWeb.Dispose();
            }
        }
        #endregion

        /// <summary>
        /// Gets the edit permissions URL. This URL is a link to the sharepoint page used to manage permissions for
        /// a securable object.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="webURL">The web URL.</param>
        /// <returns></returns>
        private string GetEditPermissionsURL(Object obj, string webURL)
        {
            if (webURL.EndsWith("/"))
                webURL = webURL.Substring(0, webURL.Length - 1);

            if (obj is SPList)
            {
                SPList list = (SPList)obj;
                string guid = SPHttpUtility.UrlKeyValueEncode(list.ID.ToString("B").ToUpper());

                if ((list.BaseType == SPBaseType.DocumentLibrary) && (list.BaseTemplate != SPListTemplateType.WebPartCatalog))
                {
                    return webURL + "/_layouts/user.aspx?obj=" + guid + ",doclib&List=" + guid;
                }
                else
                    return webURL + "/_layouts/user.aspx?obj=" + guid + ",list&List=" + guid;
            }
            else if (obj is SPWeb)
            {
                return webURL + "/_layouts/user.aspx";
            }

            throw new ApplicationException(string.Format("{0} GetEditPermissionsURL:\r\n{1}",
                Properties.Resources.Error_In,
                Properties.Resources.Object_Type_Not_Supported));
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Initializes a new instance of the <see cref="SPPermissionsTreeView"/> class.
        /// </summary>
        /// <param name="siteGuid">SPSite GUID of the root web.</param>
        /// <param name="webGuid">GUID of the SPWeb that is to be the root node of the permission tree.</param>
        public SPPermissionsTreeView(Guid siteGuid, Guid webGuid) 
        {
            this._siteGuid = siteGuid;
            this._webGuid.Push(webGuid);
        }

        /// <summary>
        /// Generate the SPPermissionsTreeView nodes in 'User' mode.
        /// </summary>
        /// <param name="displaySubWebs">if set to <c>true</c> [display sub webs].</param>
        /// <param name="filterState">Determines which nodes in the tree should be filtered out.</param>
        /// <param name="userInfo">Specifies the User that the permission tree is generated for. This property is null if the _Mode is 'Web', i.e. Permission Inheritance mode.</param>
        /// <param name="basePermissions">Specifices the permission masks that the User needs to have on each SharePoint object that is checked for access. This property is null if the _Mode is 'Web', i.e. Permission Inheritance mode.</param>
        public void GenerateUserAccessTree(bool displaySubWebs, TreeNodeFilterState filterState, SPPrincipalInfo userInfo, SPBasePermissions basePermissions)
        {
            this._Mode = AccessCheckerMode.User;
            this._BasePermissions = basePermissions;
            this._PrincipalInfo = userInfo;

            GenerateTree(displaySubWebs, filterState);
        }

        /// <summary>
        /// Generate the SPPermissionsTreeView nodes in 'Web' (Permission Inheritance) mode.
        /// </summary>
        /// <param name="displaySubWebs">if set to <c>true</c> [display sub webs].</param>
        /// <param name="filterState">Determines which nodes in the tree should be filtered out.</param>
        public void GeneratePermissionInheritanceTree(bool displaySubWebs, TreeNodeFilterState filterState)
        {
            this._Mode = AccessCheckerMode.Web;

            GenerateTree(displaySubWebs, filterState);
        }
        /// <summary>
        /// Get a javascript block used to colour code tree nodes for this TreeView.
        /// </summary>
        /// <param name="treeViewID">The TreeView clientID.</param>
        /// <returns></returns>
        public string GetColourCodingScript()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(@"
<script type=""text/javascript"">
_spBodyOnLoadFunctionNames.push(""ACWP_ApplyColouringToTreeNodes_TREEVIEWID"");
");
            // Create variables to hold alt text for images            
            sb.Append("var greenAltText = \"" + Properties.Resources.ResourceManager.GetString(this._Mode.ToString() + "_greenAltText", Properties.Resources.Culture) + "\";");
            sb.Append("var greenRedAltText = \"" + Properties.Resources.ResourceManager.GetString(this._Mode.ToString() + "_greenRedAltText", Properties.Resources.Culture) + "\";");
            sb.Append("var redAltText = \"" + Properties.Resources.ResourceManager.GetString(this._Mode.ToString() + "_redAltText", Properties.Resources.Culture) + "\";");
            sb.Append("var redGreenAltText = \"" + Properties.Resources.ResourceManager.GetString(this._Mode.ToString() + "_redGreenAltText", Properties.Resources.Culture) + "\";");

            sb.Append(@"
function ACWP_InsertTextualInfo_TREEVIEWID(divElem, trNode, permissionsString, userOrWebPermissions)
{
    var s = """";

    if (permissionsString.match(""DIFFERENT_PERMISSIONS""))
    {
        // Colour link text
        divElem.parentNode.className += "" ACWP-DifferentPermissionsText"";
        if (userOrWebPermissions == ""User"")
        {
            s += ""<img src=\""/_layouts/images/AccessChecker/red.PNG\"" alt=\"""" + redAltText + ""\"" />"";
        }
    }
    else if (permissionsString.match(""MATCHING_PERMISSIONS""))
    {
        // Colour link text. Parent node is the <a> tag containing the link text
        divElem.parentNode.className += "" ACWP-MatchingPermissionsText"";
        if (userOrWebPermissions == ""User"")
        {
            s += ""<img src=\""/_layouts/images/AccessChecker/green.PNG\"" alt=\"""" + greenAltText + ""\"" />"";
        }
    }
    
    var newTD = document.createElement('td');
    trNode.insertBefore(newTD, trNode.firstChild);
    newTD.innerHTML = s;
    newTD.setAttribute('height', '100%');
    newTD.setAttribute('style', 'vertical-align:middle');
}
");

            sb.Append(@"
function ACWP_ApplyColouringToTreeNodes_TREEVIEWID()
{	        
    var treeView = document.getElementById(""TREEVIEWID"");
    
    <!-- Check if the tree view control exists before attempting to colour code nodes -->
    if (treeView != null)
    {
        var divElems = treeView.getElementsByTagName(""div"");
        for (i=0; i<divElems.length; i++)
	    {	  
	        if (divElems[i].className == ""ACWP-TreeNodeValuePath"")
		    {   
                    var valuePath;

                    if (document.all){
                       valuePath = divElems[i].innerText.split(""|"");  
                    }
                    else {
                       valuePath = divElems[i].textContent.split(""|"");     
                    }
		   
                    ACWP_InsertTextualInfo_TREEVIEWID(divElems[i], divElems[i].parentNode.parentNode.parentNode, valuePath[valuePath.length-1], treeView.ShowUserOrWebPermissions);   				    			    				              
		    }
	    }
    }
}
</script>
");
            sb.Replace("TREEVIEWID", this.ClientID);
            sb.Replace("DIFFERENT_PERMISSIONS", PermissionType.DifferentPermissions.ToString());
            sb.Replace("MATCHING_PERMISSIONS", PermissionType.MatchingPermissions.ToString());
            return sb.ToString();
        }

        /// <summary>
        /// Append the valuePath property to the Text property value, for the specified node and its children.
        /// </summary>
        /// <param name="recursive">Apply to all child nodes</param>
        public void AppendTreeNodeValuePathToText(TreeNode node)
        {
            foreach (TreeNode childNode in node.ChildNodes)
            {
                AppendTreeNodeValuePathToText(childNode);
            }
            node.Text += valuePathDivTagStart + node.ValuePath + valuePathDivTagEnd;
        }

        /// <summary>
        /// Remove the valuePath property from the Text property value, for the specified node and its children.
        /// </summary>
        /// <param name="recursive">Apply to all child nodes</param>
        public void RemoveTreeNodeValuePathFromText(TreeNode node)
        {
            foreach (TreeNode childNode in node.ChildNodes)
            {
                RemoveTreeNodeValuePathFromText(childNode);
            }
            node.Text = node.Text.Replace(valuePathDivTagStart + node.ValuePath + valuePathDivTagEnd, "");
        }
        #endregion
    }     
}